package com.zwh.se.io.bio;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author yexi
 * 从先需要启动服务器才能正常处理请求信息这点可以得知在TCP的之间客户端和服务端之间的地位是不同等的(服务器必须开着并一直进行请求才可以)
 */
public class SocketServer {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        Socket acceptSocket = null;
        try {
            //创建一个服务端对象(ServerSocket)
            serverSocket = new ServerSocket(8080);
            //死循环,让服务器一直监听客户端是否发送数据
            while (true) {
                //监听客户端的连接,获取和客户端通信的Socket对象
                //此方法调用后会直接堵塞(堵塞方法),直至有监听到socket对象有数据后才会继续执行后续逻辑(当接收到socket后,就可以认为客户端与服务端产生了连接)
                acceptSocket = serverSocket.accept();
                //优化模型(指通过多线程处理):不做优化的话,也就是不开多线程,功能一样可以生效,但是理解一下就可以知道,这样相当于在
                //   accept()调用之后堵塞,然后处理完所有客户端的信息并返回之后,才能够再次accept()继续监听,这样效率就被浪费了,所以采用多线程来处理
                new ServerThread(acceptSocket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    private static void lookSocketState(Socket socket) {
        //查看socket状态
        System.out.println("socket.isInputShutdown() = " + socket.isInputShutdown());
        System.out.println("socket.isBound() = " + socket.isBound());
        System.out.println("socket.isClosed() = " + socket.isClosed());
        System.out.println("socket.isConnected() = " + socket.isConnected());
        System.out.println("socket.isOutputShutdown() = " + socket.isOutputShutdown());
    }

    static class ServerThread extends Thread {

        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        OutputStream outputStream = null;
        Socket acceptSocket = null;
        DataInputStream dataInputStream = null;

        public ServerThread(Socket socket) {
            acceptSocket = socket;
        }

        @Override
        public void run() {
            try {
                //先查看下socket状态,以方便理解之后的shutdownInput和shutdownOutput
                lookSocketState(acceptSocket);
                //从Socket获取输入流,接收服务器发送的数据
                inputStream = acceptSocket.getInputStream();
                //为了方便直接使用缓冲流阅读了,如果不懂相关知识请先去补充IO知识
                dataInputStream = new DataInputStream(inputStream);
                bufferedReader = new BufferedReader(new InputStreamReader(dataInputStream));
                String msg = bufferedReader.readLine();
                //请勿使用这个判断,如果要测试http的话,这个判断条件会由于有取到""而导致下面的.readLine()方法堵塞的情况出现,目前笔者暂未理解为什么会有这种问题,所以先用着解决方案先
                while (msg != null) {
//                while (!msg.isEmpty()) {
                    System.out.println(msg);
                    msg = bufferedReader.readLine();
                }
                //调用Socket对象的shutdownInput方法通知客户端数据接收完毕
                acceptSocket.shutdownInput();
                System.out.println("acceptSocket.isInputShutdown() = " + acceptSocket.isInputShutdown());
                //从Socket中拿到输出流往客户端发送数据
                outputStream = acceptSocket.getOutputStream();
                //outputStream.write("服务器已接收到客户端信息,over".getBytes(StandardCharsets.UTF_8));
                BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
                bufferedWriter.write("HTTP/1.1 200 ok\n\nHello World!\n");
                bufferedWriter.flush();
                //调用Socket对象的shutdownOutput方法通知客户端数据发送完毕
                acceptSocket.shutdownOutput();
                System.out.println("acceptSocket.isOutputShutdown() = " + acceptSocket.isOutputShutdown());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //关闭流+关闭Socket对象(关闭网络资源)
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (bufferedReader != null) {
                        bufferedReader.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (outputStream != null) {
                        outputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (acceptSocket != null) {
                        acceptSocket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (dataInputStream != null) {
                        dataInputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
